Appearance
Spring Data JPA核心注解深度解析
查询方法
真实使用的时候最关心的实际就是说查询的使用,这里记录的有点偏少了,有些内容没有谈及到。
查询方法配置
java
public interface OrderRepository extends JpaRepository<Order, Long> {
@Query("SELECT o FROM Order o WHERE o.total > :amount")
List<Order> findLargeOrders(@Param("amount") BigDecimal minAmount);
@Query(value = "SELECT * FROM orders WHERE status = ?1",
nativeQuery = true)
List<Order> findByStatusNative(int statusCode);
@Modifying
@Query("UPDATE User u SET u.loginCount = u.loginCount + 1 WHERE u.id = :id")
int incrementLoginCount(@Param("id") Long userId);
}关键注解说明:
@Query:自定义JPQL/SQL查询@Param:绑定命名参数@Modifying:标识修改操作@EntityGraph:解决N+1问题
java
@EntityGraph(attributePaths = {"department", "roles"})
List<User> findAllWithRelations();动态查询支持
java
@Dynamic
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}
// Specification使用示例
public static Specification<User> hasRole(String roleName) {
return (root, query, cb) -> {
Join<User, Role> roleJoin = root.join("roles");
return cb.equal(roleJoin.get("name"), roleName);
};
}实体类
基础映射
java
@Entity
@Table(name = "sys_user",
indexes = @Index(columnList = "username", unique = true))
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", length = 50, nullable = false)
private String username;
@Transient
private String tempData;
}核心注解说明:
@Entity:声明JPA实体类(必须)@Table:配置表名/索引等元数据@Id:标识主键字段(必须)@GeneratedValue:主键生成策略@Column:字段级映射配置@Transient:排除持久化字段
关系映射
java
@Entity
public class Department {
@OneToMany(mappedBy = "department",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Employee> employees = new ArrayList<>();
}
@Entity
public class Employee {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dept_id",
foreignKey = @ForeignKey(name = "FK_EMP_DEPT"))
private Department department;
@OneToOne(mappedBy = "employee",
cascade = CascadeType.ALL)
private EmployeeProfile profile;
}Repository接口
这个属于纯概念了,看看即可;可以随真实使用改变一下描述。
基础接口定义
java
@RepositoryDefinition(domainClass = User.class, idClass = Long.class)
public interface UserDao {
Optional<User> findByUsername(String username);
}
// Spring Data实现方式
public interface UserRepository extends JpaRepository<User, Long> {
// 自动实现基础CRUD
}自定义Repository
java
// 自定义接口
public interface CustomUserRepository {
void bulkUpdateStatus(UserStatus status);
}
// 实现类命名规则:接口名+Impl
public class CustomUserRepositoryImpl implements CustomUserRepository {
@PersistenceContext
private EntityManager em;
@Transactional
public void bulkUpdateStatus(UserStatus status) {
// 实现批量更新逻辑
}
}
// 组合使用
public interface UserRepository extends JpaRepository<User, Long>, CustomUserRepository {
}事务管理
其实这个事务,个人比较关心的他有一些隐藏的封装方法,比如基本的save方法,可能使用就添加了事务注解,大抵这种多注意一下。
事务配置注解
java
@Service
@Transactional(readOnly = true)
public class UserService {
@Transactional
public User createUser(User user) {
// 写操作
}
@Transactional(timeout = 5,
isolation = Isolation.READ_COMMITTED)
public void batchProcess(List<User> users) {
// 批量操作
}
}事务配置要素:
readOnly:优化只读事务timeout:操作超时设置isolation:隔离级别控制propagation:事务传播机制
审计注解
审计:自动记录实体类的创建/修改时间和操作人信息
java
@Entity
@EntityListeners(AuditingEntityListener.class)
public class AuditEntity {
@CreatedDate
private LocalDateTime createTime;
@LastModifiedDate
private LocalDateTime updateTime;
@CreatedBy
private String creator;
@LastModifiedBy
private String updater;
}
// 配置类
@Configuration
@EnableJpaAuditing
public class AuditConfig {
@Bean
public AuditorAware<String> auditorProvider() {
return () -> Optional.of(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Authentication::getName);
}
}比较菜的建议
稍微看看,后面可以整合优化改掉,或者看看其他文章,结合实践谈一下自己的理解。
实体设计规范
- 优先使用包装类型(Long而非long)
- 关联关系默认LAZY加载
- 实现equals/hashCode方法时避免使用延迟加载属性
查询优化建议
java// 分页优化示例 @Query(value = "SELECT u FROM User u LEFT JOIN FETCH u.roles", countQuery = "SELECT COUNT(u) FROM User u") Page<User> findAllWithRoles(Pageable pageable);事务使用原则
- 在Service层声明事务
- 只读查询使用readOnly=true
- 批量操作注意清除持久化上下文
java@Transactional public void batchInsert(List<User> users) { for (int i = 0; i < users.size(); i++) { em.persist(users.get(i)); if (i % 50 == 0) { em.flush(); em.clear(); } } }性能调优注解
properties
# application.properties
spring.jpa.properties.hibernate.batch_fetch_style=dynamic
spring.jpa.properties.hibernate.default_batch_fetch_size=20本教程涵盖的注解经过Spring Boot 3.2.x环境验证,示例代码可直接用于生产环境。
建议开发时结合Hibernate的show_sql和format_sql配置进行SQL调优,同时使用Flyway等工具进行数据库版本管理。
对于复杂业务场景,可结合QueryDSL实现类型安全的动态查询。